﻿using System;
using System.Diagnostics;
using System.Threading;

namespace ExcelDna.AddIn.Tasks.IntegrationTests.Utils
{
    internal static class SilentProcessRunner
    {
        public static int ExecuteCommand(string executable, string arguments, string workingDirectory, Action<string> output, Action<string> error)
        {
            try
            {
                using (var process = new Process())
                {
                    process.StartInfo.FileName = executable;
                    process.StartInfo.Arguments = arguments;
                    process.StartInfo.WorkingDirectory = workingDirectory;
                    process.StartInfo.UseShellExecute = false;
                    process.StartInfo.CreateNoWindow = true;
                    process.StartInfo.RedirectStandardOutput = true;
                    process.StartInfo.RedirectStandardError = true;

                    using (var outputWaitHandle = new AutoResetEvent(false))
                    {
                        using (var errorWaitHandle = new AutoResetEvent(false))
                        {
                            process.OutputDataReceived += (sender, e) =>
                            {
                                if (e.Data == null)
                                {
                                    // ReSharper disable once AccessToDisposedClosure
                                    outputWaitHandle.Set();
                                }
                                else
                                {
                                    output(e.Data);
                                }
                            };

                            process.ErrorDataReceived += (sender, e) =>
                            {
                                if (e.Data == null)
                                {
                                    // ReSharper disable once AccessToDisposedClosure
                                    errorWaitHandle.Set();
                                }
                                else
                                {
                                    error(e.Data);
                                }
                            };

                            process.Start();

                            process.BeginOutputReadLine();
                            process.BeginErrorReadLine();

                            process.WaitForExit();
                            outputWaitHandle.WaitOne();
                            errorWaitHandle.WaitOne();

                            return process.ExitCode;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(string.Format("Error when attempting to execute {0}: {1}", executable, ex.Message), ex);
            }
        }
    }
}
